﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSConsoleTest
{
    class TestLinQ : BaseConsoleTest
    {
        public void printDescription()
        {
            Console.WriteLine("--- LinQ ---"); 
        }

        public void doTest()
        {
            Weapon[] weapons = new Weapon[] {
                new Weapon(){Name="Fire sword", Type=EWeaponType.eTYPE_SWORD, Power=50, Price=300, 
                    Ability=new EWeaponAbility[]{EWeaponAbility.eABILITY_FIRE}},
                new Weapon(){Name="wind sword", Type=EWeaponType.eTYPE_SWORD, Power=50, Price=300, 
                    Ability=new EWeaponAbility[]{EWeaponAbility.eABILITY_WIND}},
                new Weapon(){Name="IceWind sword", Type=EWeaponType.eTYPE_SWORD, Power=50, Price=300, 
                    Ability=new EWeaponAbility[]{EWeaponAbility.eABILITY_ICE, EWeaponAbility.eABILITY_WIND}},

                new Weapon(){Name="Fire gun", Type=EWeaponType.eTYPE_GUN, Power=80, Price=500, 
                    Ability=new EWeaponAbility[]{EWeaponAbility.eABILITY_FIRE}},
                new Weapon(){Name="Ice gun", Type=EWeaponType.eTYPE_GUN, Power=80, Price=500, 
                    Ability=new EWeaponAbility[]{EWeaponAbility.eABILITY_ICE}},
                new Weapon(){Name="IceLightning gun", Type=EWeaponType.eTYPE_GUN, Power=80, Price=500, 
                    Ability=new EWeaponAbility[]{EWeaponAbility.eABILITY_ICE, EWeaponAbility.eABILITY_LIGHTNING}},

                new Weapon(){Name="Light Axe", Type=EWeaponType.eTYPE_AXE, Power=120, Price=500, 
                    Ability=new EWeaponAbility[]{EWeaponAbility.eABILITY_LIGHT}},
                new Weapon(){Name="Dark Axe", Type=EWeaponType.eTYPE_AXE, Power=120, Price=500, 
                    Ability=new EWeaponAbility[]{EWeaponAbility.eABILITY_DARK}},
                new Weapon(){Name="DarkFire Axe", Type=EWeaponType.eTYPE_AXE, Power=120, Price=500, 
                    Ability=new EWeaponAbility[]{EWeaponAbility.eABILITY_DARK, EWeaponAbility.eABILITY_FIRE}},

                new Weapon(){Name="Light Knife", Type=EWeaponType.eTYPE_KNIFE, Power=120, Price=500, 
                    Ability=new EWeaponAbility[]{EWeaponAbility.eABILITY_LIGHT}},
                new Weapon(){Name="Dark Axe", Type=EWeaponType.eTYPE_KNIFE, Power=120, Price=500, 
                    Ability=new EWeaponAbility[]{EWeaponAbility.eABILITY_DARK}},
                new Weapon(){Name="DarkFire Axe", Type=EWeaponType.eTYPE_KNIFE, Power=120, Price=500, 
                    Ability=new EWeaponAbility[]{EWeaponAbility.eABILITY_DARK, EWeaponAbility.eABILITY_FIRE}},
            };

            WeaponTypeProp[] weaponTypeProp = new WeaponTypeProp[] {  
                new WeaponTypeProp(){Type=EWeaponType.eTYPE_KNIFE, PowerRatio=0.5f, SpeedRatio=1.7f},
                new WeaponTypeProp(){Type=EWeaponType.eTYPE_GUN, PowerRatio=0.8f, SpeedRatio=1.2f},
                new WeaponTypeProp(){Type=EWeaponType.eTYPE_SWORD, PowerRatio=0f, SpeedRatio=0f},
                new WeaponTypeProp(){Type=EWeaponType.eTYPE_AXE, PowerRatio=1.8f, SpeedRatio=0.6f},
            };

            Console.WriteLine("- Basic query");
            var resultSet1 = from weapon in weapons
                          where weapon.Type == EWeaponType.eTYPE_GUN
                          orderby weapon.Name
                          select new { WeaponName=weapon.Name, WeaponPrice=weapon.Price };
            foreach (var result1 in resultSet1)
            {
                Console.WriteLine("\tName : {0}, Price : {1}", result1.WeaponName, result1.WeaponPrice);
            }

            Console.WriteLine("- Nested query");
            var resultSet2 = from weapon in weapons
                             from weaponAbility in weapon.Ability
                             where weaponAbility == EWeaponAbility.eABILITY_FIRE
                             orderby weapon.Name
                             select new { WeaponName = weapon.Name, WeaponPrice = weapon.Price, WeaponAvbility = weaponAbility };
            foreach (var result2 in resultSet2)
            {
                Console.WriteLine("\tName : {0}, Price : {1} Ability = {2}", result2.WeaponName, result2.WeaponPrice, result2.WeaponAvbility);
            }

            Console.WriteLine("- Group query");
            var resultSet3 = from weapon in weapons
                             orderby weapon.Name
                             group weapon by weapon.Type into weaponGroups
                             select weaponGroups;
            foreach (IGrouping<EWeaponType, Weapon> result3 in resultSet3)
            {
                Console.WriteLine("Weapon group : {0}", result3.Key);
                foreach (Weapon weapon in result3)
                {
                    Console.WriteLine("\t{0}", weapon);
                }
            }

            Console.WriteLine("- Inner join query");
            var resultSet4 = from weapon in weapons
                             join typeProp in weaponTypeProp on weapon.Type equals typeProp.Type
                             orderby weapon.Name
                             select weapon;
            foreach (Weapon result4 in resultSet4)
            {
                Console.WriteLine("\t{0}", result4);
            }

            Console.WriteLine("- Outer left join query");
            var resultSet5 = from weapon in weapons
                             join typeProp in weaponTypeProp on weapon.Type equals typeProp.Type into joinResult
                             from typeProp in joinResult.DefaultIfEmpty(new WeaponTypeProp() { SpeedRatio = 0, PowerRatio = 0 })
                             orderby weapon.Name
                             select new {weapon, typeProp};
            foreach (var result5 in resultSet5)
            {
                Console.Write("\t{0}", result5.weapon);
                Console.Write(" {0}", result5.typeProp);
                Console.WriteLine();
            }
        }
    }

    class Weapon
    {
        public EWeaponType Type { set; get; }
        public EWeaponAbility[] Ability { set; get; }
        public string Name { set; get; }
        public int Power { set; get; }
        public double Price { set; get; }

        public override string ToString()
        {
            return "Name : " + Name + " Power : " + Power + " Price : " + Price + " Ability : " + Ability;
        }
    }

    class WeaponTypeProp
    {
        public EWeaponType Type { set; get; }
        public float SpeedRatio { set; get; }
        public float PowerRatio { set; get; }

        public override string ToString()
        {
            return "SppedRatio : " + SpeedRatio + " PowerRatio : " + PowerRatio;
        }
    }

    enum EWeaponType
    {
        eTYPE_GUN,
        eTYPE_KNIFE,
        eTYPE_SWORD,
        eTYPE_AXE,
        eTYPE_MISSLE
    }

    enum EWeaponAbility
    {
        eABILITY_EARCH,
        eABILITY_FIRE,
        eABILITY_WIND,
        eABILITY_WATER,
        eABILITY_LIGHT,
        eABILITY_DARK,
        eABILITY_ICE,
        eABILITY_LIGHTNING
    }
}
